﻿using System;
//using System.Collections.Generic;
//using System.Text;

namespace Stauffware.Common.Core
{
	//#################################################################################
	/// <summary>
	/// Base class for all Parse classes.
	/// </summary>

	public abstract class Parse<T> : IParse<T>
	{
		/// <summary>
		/// <see cref="IParse.GotValue"/>
		/// </summary>
		public abstract bool GotValue { get; }

		/// <summary>
		/// <see cref="IParse.IsError"/>
		/// </summary>
		public bool IsError { get { return this._errorMessage != null; } }

		/// <summary>
		/// <see cref="IParse.IsEmpty"/>
		/// </summary>
		public bool IsEmpty { get { return (!this.GotValue) && (this._errorMessage == null); } }

		/// <summary>
		/// <see cref="IParse&lt;T&gt;.Value"/>
		/// </summary>
		public abstract T Value { get; }

		/// <summary>
		/// <see cref="IParse.ErrorMessage"/>
		/// </summary>
		public string ErrorMessage { get { return this._errorMessage; } }

		/// <summary>
		/// <see cref="IParse.ParsedText"/>
		/// </summary>
		public string ParsedText { get { return this._parsedText; } }

		/// <summary>
		/// <see cref="IParse.ToException"/>
		/// </summary>
		public virtual ParseException ToException ()
		{
			return (this._errorMessage == null) ? null : 
					new ParseException(this._errorMessage, this._parsedText);
		}

		/// <summary>
		/// Implicit cast from a Parse&lt;T&gt; to its target type T, 
		/// returning the result of the parse.
		/// </summary>
		/// <param name="r">the parse object</param>
		/// <returns>the parsed value</returns>
		public static implicit operator T (Parse<T> r) { return r.Value; }

		/// <summary>
		/// Implicit cast from a Parse&lt;T&gt; to an exception, using the
		/// error message from the parse object.  This allows an unsuccessful
		/// parse object to be used directly in a throw statement.
		/// </summary>
		/// <param name="r">the parse object</param>
		/// <returns>an exception containing the parse error</returns>

		public static implicit operator Exception (Parse<T> r)
		{
			Require.NotNull(r._errorMessage, "Parse was successful");
			return r.ToException();
		}

		/// for debugging, mainly
		public override string ToString ( )
		{
			if (this.GotValue)
				return this.GetType().Name + " { " + ErrorUtils.ValueToString(this.Value) + " }";
			if (this.IsError)
				return this.GetType().Name + " { " + ErrorUtils.ValueToString(this._errorMessage) + " }";
			return this.GetType().Name + " {EMPTY}";
		}

		/// <summary>
		/// The error message, or null.
		/// </summary>
		protected internal string _errorMessage;

		/// <summary>
		/// The parsed text.
		/// </summary>
		protected internal string _parsedText;

	}

	//#################################################################################
	/// <summary>
	/// Base class for all Parse classes that produce a pass-by-value type.
	/// </summary>

	public abstract class ValueParse<T> : Parse<T> where T : struct
	{
		/// <summary>
		/// <see cref="IParse&lt;T&gt;.Value"/>
		/// </summary>
		public sealed override T Value
		{
			get
			{
				Require.Condition(this._value.HasValue, this.GetType().Name + " has no value");
				return this._value.Value;
			}
		}

		/// <summary>
		/// <see cref="IParse.GotValue"/>
		/// </summary>
		public sealed override bool GotValue { get { return this._value.HasValue; } }

		/// <summary>
		/// the parsed value
		/// </summary>
		protected internal T? _value;
	}

	//#################################################################################
	/// <summary>
	/// Base class for all Parse classes that produce a pass-by-reference type (object).
	/// </summary>

	public abstract class ReferenceParse<T> : Parse<T> where T : class
	{
		/// <summary>
		/// <see cref="IParse&lt;T&gt;.Value"/>
		/// </summary>
		public sealed override T Value
		{
			get
			{
				Require.NotNull(this._value);
				return this._value;
			}
		}

		/// <summary>
		/// <see cref="IParse.GotValue"/>
		/// </summary>
		public sealed override bool GotValue { get { return this._value != null; } }

		/// <summary>
		/// the parsed value, or null
		/// </summary>
		protected internal T _value;
	}

	//#################################################################################
}
